
//canok 20210316 
//NdkMediacodec.cpp
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#include <unistd.h>
#include "media/NdkMediaCodec.h"

#define LOGD printf
//bool bRun = true;
AMediaCodec* pMediaCodec;
AMediaFormat *format ; /* 
			  FILE *fp_in = NULL;
			  FILE *fp_out = NULL;*/ 
int mW = 1440;
int mH=1080;
int ext=0; 
int64_t getNowUs(){
	timeval tv;
	gettimeofday(&tv, 0);
	return (int64_t)tv.tv_sec * 1000000 + (int64_t)tv.tv_usec;
}

int initbian(){
	/*  
	    fp_in = fopen("/storage/emulated/0/canok/1080p60.yuv","r");
	    if(NULL == fp_in){
	    LOGD("[%s][%d]fopen erro, no inputfile!\n",__FUNCTION__ ,__LINE__);
	    exit(-1);
	    }
	    fp_out = fopen("/storage/emulated/0/canok/out_1080p60.h264","w+");
	    if(NULL == fp_out){
	    LOGD("[%s][%d]fopen erro\n",__FUNCTION__ ,__LINE__);
	    exit(-1);
	    }
	    */ 
	//https://github.com/android/ndk-samples/blob/main/native-codec/app/src/main/cpp/native-codec-jni.cpp
	//decode
	//这里设定名称
	pMediaCodec = AMediaCodec_createEncoderByType("video/avc");//h264 // 创建 codec 编码器
	if(pMediaCodec == NULL){
		LOGD("createEncoder erro[%s%d]\n",__FUNCTION__ ,__LINE__);
	}
	format = AMediaFormat_new();
	/*
	   AMediaFormat_setInt32(format,"encoder",1);
	   AMediaFormat_setInt32(format,"color-format",2130708361);
	   AMediaFormat_setString(format, "mime", "video/avc"); 
	   AMediaFormat_setInt32(format,AMEDIAFORMAT_KEY_WIDTH,mW);
	   AMediaFormat_setInt32(format,AMEDIAFORMAT_KEY_HEIGHT,mH);
	//在OMX_IVCommon.h https://www.androidos.net.cn/android/9.0.0_r8/xref/frameworks/native/headers/media_plugin/media/openmax/OMX_IVCommon.h
	// AMediaFormat_setInt32(format,AMEDIAFORMAT_KEY_COLOR_FORMAT,OMX_COLOR_FormatYUV420Planar);
	AMediaFormat_setInt32(format,AMEDIAFORMAT_KEY_COLOR_FORMAT,0);
	AMediaFormat_setInt32(format,"android._encoding-quality-level",1);
	AMediaFormat_setInt32(format,AMEDIAFORMAT_KEY_FRAME_RATE,25); 
	AMediaFormat_setInt32(format,AMEDIAFORMAT_KEY_BIT_RATE,4000*1000);
	AMediaFormat_setInt32(format,AMEDIAFORMAT_KEY_I_FRAME_INTERVAL,5);  
	*/
#define COLOR_FormatYUV420Planar  0x00000013  //对应安卓
#define COLOR_FormatYUV420Flexible 0x7f420888
#define COLOR_FormatSurface 2130708361  //（0x7f000789）  1440x1080
					// for(int i=0;i<2130708361; i++){
	AMediaFormat_setInt32(format,"color-format", /*2130708361*//*0x7fa30c00*/COLOR_FormatYUV420Flexible);
	AMediaFormat_setInt32(format,"i-frame-interval", 1);
	AMediaFormat_setInt32(format,"level", 65536);
	AMediaFormat_setString(format,"mime", "video/avc");
	AMediaFormat_setInt32(format,"profile" ,8);
	AMediaFormat_setInt32(format,"width", 1440);
	AMediaFormat_setInt32(format,"bitrate" ,1440*1080);
	AMediaFormat_setInt32(format,"frame-rate" ,30);
	AMediaFormat_setInt32(format,"height", 1080);

	//printf("[%s][%s][%d]fromat:%s\n",__FUNCTION__ ,__DATE__,__LINE__,AMediaFormat_toString(format));

	//这里配置 format
	media_status_t status = AMediaCodec_configure(pMediaCodec,format,NULL,NULL,AMEDIACODEC_CONFIGURE_FLAG_ENCODE);//解码，flags 给0，编码给AMEDIACODEC_CONFIGURE_FLAG_ENCODE
	/*if(status==0){
	  printf("ok %d\n",i);  
	  }*/ 
	//}

	if(status!=0){
		printf("erro config %d\n",status);
		return NULL;
	}
	AMediaCodec_start(pMediaCodec);
	if(status!=0){
		LOGD("start erro %d\n",status);
		return NULL;
	}
	return 1; 
}
size_t outsize;
int in_frame=0;                                                                                                                     int out_frame=0;                                                                                                                    int64_t lastOuttime=0;                                                                                                              char i=0;                                                                                                                           char buff[1024];
ssize_t bufidx;
size_t bufsize;
int64_t pts ;
uint8_t *buf=0;
int frameLenYuv = mW * mH * 3 / 2;
int32_t frameRate,w,h,color;
int64_t nowtime;
int  outindex ; 
int getbian(){
	/* int ret=initbian();
	if(ret!=1) 
		return 0; */ 
	/*
		 int in_frame=0;
		 int out_frame=0;
		 int64_t lastOuttime=0;
		 char i=0; 
		 char buff[1024]; */ 
	while(1){
		/* 
		   if(feof(fp_in)){
		   ext=1; 
		   break; 
		   }*/ 
		//请求buffer
		bufidx = AMediaCodec_dequeueInputBuffer(pMediaCodec, 2000 );
		//LOGD("input buffer %zd\n",bufidx);
		if(bufidx>=0) {
			pts = getNowUs();
			buf = AMediaCodec_getInputBuffer(pMediaCodec, bufidx, &bufsize);
			//填充yuv数据
			//int frameLenYuv = mW * mH * 3 / 2;
			memset(buf,i,frameLenYuv);
			in_frame++; 
			i++;
			if(i==255) 
				i=0; 
			/* 
			   if (fread(buf, 1, frameLenYuv, fp_in) < frameLenYuv) {
			   break; 
			//fseek(fp_in, 0, SEEK_SET);
			//fread(buf, 1, frameLenYuv, fp_in);
			}*/ 
			//入队列
			//LOGD("in[%d] pts:%lld\n", in_frame++, pts);
			AMediaCodec_queueInputBuffer(pMediaCodec, bufidx, 0, frameLenYuv, pts, 2000);
		}

		AMediaCodecBufferInfo info;
		//取输出buffer
		outindex = AMediaCodec_dequeueOutputBuffer(pMediaCodec, &info, 0) ;
		if (outindex >= 0) {
			//在这里取走编码后的数据
			//释放buffer给编码器
			//size_t outsize;
			buf = AMediaCodec_getOutputBuffer(pMediaCodec,outindex,&outsize);
			fprintf(stderr,"写入文件size %d\n",info.size); 
			//fwrite(buf,1,info.size,fp_out);
			write(1,"ok",2); 
			write(1,&(info.size) ,sizeof(int)); 
			write(1,buf,info.size);
			if(1) {
				AMediaFormat *format2 = AMediaCodec_getOutputFormat(pMediaCodec);
				//int32_t frameRate,w,h,color;
				AMediaFormat_getInt32(format2,AMEDIAFORMAT_KEY_FRAME_RATE,&frameRate);
				AMediaFormat_getInt32(format2,AMEDIAFORMAT_KEY_WIDTH,&w);
				AMediaFormat_getInt32(format2,AMEDIAFORMAT_KEY_HEIGHT,&h);
				sprintf(buff,"out[%d]in[%d] pts %lld %dX%d@%d %d \r",out_frame++,in_frame,info.presentationTimeUs,w,h,frameRate,info.size);
				write(2,buff,strlen(buff));
				nowtime = getNowUs();
				// fprintf(stderr,"frame stay times:%lld,  out_gap:%lld\n",nowtime-info.presentationTimeUs,nowtime-lastOuttime);
				lastOuttime = nowtime;
			}
			AMediaCodec_releaseOutputBuffer(pMediaCodec, outindex, false);
		}
	//	usleep(10000); 
	}

}
int main(int argc, const char*argv[]){
	int ret=1; 
	ret=initbian(); 
	int i=0; 
	while(ret==1){
		getbian();
		printf("i=%d\n",i++);
	}
	/*int ret =0;
	  pthread_t pid;
	  if((ret=pthread_create(&pid,NULL,run,NULL)) !=0 ){
	  LOGD("thread_create err\n");
	  return -1;
	  }
	  while(1){
	  usleep(1000*1000);
	  }
	  */ 
}


